Skip to content

Conversation

@ammar-agent
Copy link
Collaborator

Problem

When interrupting a stream (especially on SSH), the UI experienced a noticeable delay of 500ms-2s before responding. The user would hit Ctrl+C/Escape but the UI would remain in "streaming" state for 1-2 seconds.

Root Cause

The delay occurred because stream interruption waited for processingPromise to complete before emitting the stream-abort event. In the finally block of processStreamWithCleanup(), we were executing:

const result = await streamInfo.runtime.exec(`rm -rf "${streamInfo.runtimeTempDir}"`, {
  cwd: "~",
  timeout: 10,
});
await result.exitCode; // Wait for completion

For SSH runtimes, this meant:

  1. SSH connection to remote host
  2. Execute recursive directory deletion
  3. Wait for command completion
  4. Close SSH connection
  5. Return exit code

Even with an empty directory, this SSH round-trip takes 500ms-2s, blocking the UI update.

Solution

Made the temp directory cleanup fire-and-forget using void promise. The cleanup still happens (and errors are logged), but it no longer blocks the critical path for emitting the stream-abort event.

The change is safe because:

  • Temp directories are stream-specific (no conflicts between streams)
  • Cleanup is best-effort (failures already logged, don't affect stream)
  • No data loss (temp dir only contains tool outputs already captured in message)
  • OS cleanup as fallback

Testing

Verify with SSH workspace:

  1. Start a stream that uses tools (generates temp directory)
  2. Hit Ctrl+C to interrupt
  3. UI should respond instantly (no 1-2 second delay)
  4. Check logs to verify temp directory cleanup still happens in background

Generated with cmux

…erruption

When interrupting a stream (especially on SSH), the UI was delayed by 500ms-2s
waiting for the temp directory cleanup to complete. The cleanup involved an
SSH 'rm -rf' command that blocked the processingPromise resolution, which
delayed the stream-abort event emission.

This change makes temp directory cleanup fire-and-forget, so the stream-abort
event is emitted immediately after the stream breaks out of the processing loop,
providing instant UI feedback.

The cleanup is still guaranteed to happen (via void promise), but it no longer
blocks the critical path for UI responsiveness.

_Generated with `cmux`_
@ammario ammario merged commit e9acfae into main Oct 27, 2025
13 checks passed
@ammario ammario deleted the fix/ssh-interrupt-stream-delay branch October 27, 2025 19:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants